package log

import (
	"fmt"
	"sync"

	"github.com/fatih/color"

	sadefine "gitee.com/simplexyz/simplego/actor/define"
	aactor "github.com/asynkron/protoactor-go/actor"
)

var gConsoleWriter = mustCreateConsoleWriter(false)

type consoleWriter struct {
	colorful bool
	d        *color.Color
	i        *color.Color
	w        *color.Color
	e        *color.Color

	startedWg sync.WaitGroup

	startedOnce sync.Once

	pid *sadefine.PID

	count sync.WaitGroup
}

func mustCreateConsoleWriter(colorful bool) *consoleWriter {
	w := &consoleWriter{
		colorful: colorful,
	}

	if w.colorful {
		color.NoColor = false

		w.d = color.New(color.FgWhite)
		w.i = color.New(color.FgHiWhite)
		w.w = color.New(color.FgHiYellow)
		w.e = color.New(color.FgHiRed)
	}

	w.startedWg.Add(1)

	props := aactor.PropsFromProducer(func() aactor.Actor { return w } /*, aactor.WithMailbox(aactor.Unbounded())*/)
	if _, err := rootContext().SpawnNamed(props, "console_writer"); err != nil {
		panic(err)
	}

	writers.Store("console_writer", w)

	w.startedWg.Wait()

	return w
}

func (w *consoleWriter) Write(record IRecord) {
	w.count.Add(1)
	rootContext().Send(w.pid, record)
}

func (w *consoleWriter) Destroy() {
	rootContext().Poison(w.pid)
	w.count.Wait()
}

func (w *consoleWriter) setColorful(colorful bool) {
	rootContext().Send(w.pid, colorful)
}

func (w *consoleWriter) Receive(ctx sadefine.Context) {
	switch msg := ctx.Message().(type) {
	case IRecord:
		defer func() {
			w.count.Done()
			destroyRecord(msg)
		}()

		s := string(msg.Bytes())

		if !w.colorful {
			fmt.Print(s)
			return
		}

		switch msg.Level() {
		case LevelDebug:
			w.d.Print(s)
		case LevelInfo:
			w.i.Print(s)
		case LevelWarn:
			w.w.Print(s)
		case LevelError:
			w.e.Print(s)
		}

	case bool:
		if w.colorful == msg {
			return
		}

		w.colorful = msg

		if msg {
			color.NoColor = false

			w.d = color.New(color.FgWhite)
			w.i = color.New(color.FgHiWhite)
			w.w = color.New(color.FgHiYellow)
			w.e = color.New(color.FgHiRed)
		}

	case *sadefine.Started:
		w.startedOnce.Do(func() {
			w.pid = ctx.Self().Clone()
			w.startedWg.Done()
		})
	}
}
